package com.zxy.study.ui.behavior;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import androidx.annotation.NonNull;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.view.ViewCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.zxy.study.R;
import com.zxy.study.utils.Utils;

import java.lang.ref.WeakReference;
import java.util.Arrays;


/*
 *  @项目名：  study
 *  @包名：    com.zxy.study.ui.behavior
 *  @文件名:   MyBehavior
 *  @创建者:   zhangxy
 *  @创建时间:  2018/7/17 14:12
 *  @描述：    TODO
 */
public class MyBehavior extends CoordinatorLayout.Behavior<View> {
	private static final String TAG = MyBehavior.class.getSimpleName();

	private Context mContext;
	private WeakReference<RelativeLayout> mDependencyView;
	private WeakReference<TextView> mTvName;
	private WeakReference<TextView> mTvTempName;
	private ValueAnimator mValueAnimator;

	private int mMinHeadHeight;
	private int mMaxHeadHeight;

	private int mTitleStartX;
	private int mTitleStartY;

	private int mTitleEndX;
	private int mTitleEndY;

	private int mStartTextSize;
	private int mEndTextSize;

	public MyBehavior() {
	}

	public MyBehavior(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;

		mMinHeadHeight = context.getResources().getDimensionPixelOffset(R.dimen.top_bar_height);
		mMaxHeadHeight = context.getResources().getDimensionPixelOffset(R.dimen.dp_150);
		mStartTextSize = context.getResources().getDimensionPixelSize(R.dimen.sp_25);
		mEndTextSize = context.getResources().getDimensionPixelSize(R.dimen.sp_16);
	}

	/**
	 * 表示是否对依赖的view 进行操作
	 * @param parent
	 * @param child  绑定behavior的View
	 * @param dependency 依赖的View
	 * @return true:操作 false:不操作
	 */
	@Override
	public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
		Log.i(TAG, "layoutDependsOn: child=" + child + "   dependency=" + dependency);
		return dependency.getId() == R.id.rl_head;
	}

	/**
	 *  依赖的View 状态（如：位置、大小）发生变化时，这个方法被调用
	 * @param parent
	 * @param child
	 * @param dependency
	 * @return
	 */
	@Override
	public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
		Log.i(TAG, "onDependentViewChanged: child=" + child + "   dependency=" + dependency);

		float childY = getMaxHeadViewHeight() - getCollapsingHeight(child.getResources()) + dependency.getTranslationY();
		child.setTranslationY(childY);

		return super.onDependentViewChanged(parent, child, dependency);
	}

	/**
	 *  当coordinatorLayout 的子View试图开始嵌套滑动的时候被调用。当返回值为true的时候表明
	 *  coordinatorLayout 充当nested scroll parent 处理这次滑动，需要注意的是只有当返回值为true
	 *  的时候，Behavior 才能收到后面的一些nested scroll 事件回调（如：onNestedPreScroll、onNestedScroll等）
	 *  这个方法有个重要的参数nestedScrollAxes，表明处理的滑动的方向。
	 *
	 * @param coordinatorLayout 和Behavior 绑定的View的父CoordinatorLayout
	 * @param child  和Behavior 绑定的View
	 * @param directTargetChild
	 * @param target
	 * @param axes 嵌套滑动 应用的滑动方向，看 {@link ViewCompat#SCROLL_AXIS_HORIZONTAL},{@link ViewCompat#SCROLL_AXIS_VERTICAL}
	 * @param type
	 * @return
	 */
	@Override
	public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {
		Log.e(TAG, "onStartNestedScroll: child=" + child + "   " + "directTargetChild=" + directTargetChild + "   target=" + target + "   axes=" + axes + "   type=" + type);
		return (axes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
	}

	/**
	 * onStartNestedScroll返回true才会触发这个方法，接受滚动处理后回调，可以在这个
	 * 方法里做一些准备工作，如一些状态的重置等。
	 * @param coordinatorLayout
	 * @param child
	 * @param directTargetChild
	 * @param target
	 * @param axes
	 * @param type
	 */
	@Override
	public void onNestedScrollAccepted(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {
		Log.d(TAG, "onNestedScrollAccepted:child=" + child + "   " + "directTargetChild=" + directTargetChild + "   target=" + target + "   axes=" + axes + "   type=" + type);
		super.onNestedScrollAccepted(coordinatorLayout, child, directTargetChild, target, axes, type);
		if (mValueAnimator != null && mValueAnimator.isStarted()) {
			mValueAnimator.cancel();
		}
	}

	/**
	 * 嵌套滚动发生之前被调用（在该方法中如果已经做了处理，child没发生滑动，那么onNestedScroll 方法就不会被调用）
	 * 在nested scroll child 消费掉自己的滚动距离之前，嵌套滚动每次被nested scroll child
	 * 更新都会调用onNestedPreScroll。注意有个重要的参数consumed，可以修改这个数组表示你消费
	 * 了多少距离。假设用户滑动了100px,child 做了90px 的位移，你需要把 consumed［1］的值改成90，
	 * 这样coordinatorLayout就能知道只处理剩下的10px的滚动。
	 * @param coordinatorLayout
	 * @param child
	 * @param target
	 * @param dx  横向滚动距离
	 * @param dy  垂直滚动距离
	 * @param consumed consumed[0]:横向被消耗的距离  consumed[1]:垂直被消耗的距离
	 * @param type 引起滚动的事件类型 比如说 {@link ViewCompat#TYPE_TOUCH}
	 */
	@Override
	public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {
		Log.e(TAG, "onNestedPreScroll: child=" + child + "   target=" + target + "   dx=" + dx + "   dy=" + dy + "   consumed[0]=" + consumed[0] + "   consume[1]=" + consumed[1] + "   type=" + type);

		if (dy < 0) {
			//向下滑动不处理
			return;
		}

		View view = mDependencyView.get();
		int minTranslate = mMinHeadHeight - getMaxHeadViewHeight();
		if (view.getTranslationY() != minTranslate) {
			float newTranslationY = view.getTranslationY() - dy;
			newTranslationY = newTranslationY < minTranslate ? minTranslate : newTranslationY;

			onScroll(newTranslationY, true);
			view.setTranslationY(newTranslationY);
			consumed[1] = dy;
		}
	}

	private void onScroll(float newTranslationY, boolean scrollUp) {
		TextView tvTempView = mTvTempName.get();
		TextView tvName = mTvName.get();
		RelativeLayout dependency = mDependencyView.get();

		float translationY = dependency.getTranslationY();
		if (translationY == 0) {
			tvTempView.setVisibility(scrollUp ? View.VISIBLE : View.INVISIBLE);
			tvName.setVisibility(scrollUp ? View.INVISIBLE : View.VISIBLE);
		}else if(translationY < 0 && (tvTempView.getVisibility() != View.VISIBLE || tvName.getVisibility() != View.INVISIBLE)){
			tvTempView.setVisibility(View.VISIBLE);
			tvName.setVisibility(View.INVISIBLE);
		}

		//计算变化的比例值
		float ratio = Math.abs(newTranslationY) / (mMaxHeadHeight - mMinHeadHeight);

		//改变dependency的透明度
		dependency.setAlpha(0.3f + 1 - ratio);

		//计算名称控件移动的距离
		ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) tvTempView.getLayoutParams();
		params.leftMargin = (int) (mTitleStartX + ratio * (mTitleEndX - mTitleStartX));
		params.topMargin = (int) (mTitleStartY + ratio * (mTitleEndY - mTitleStartY));
		tvTempView.setLayoutParams(params);

		//计算字体大小
		int newTextSize = (int) (mStartTextSize + (mEndTextSize - mStartTextSize) * ratio);
		tvTempView.setTextSize(TypedValue.COMPLEX_UNIT_PX, newTextSize);
	}

	/**
	 *
	 * 进行嵌套滚动时被调用
	 * @param coordinatorLayout
	 * @param child
	 * @param target
	 * @param dxConsumed target 已经消费的x方向的距离
	 * @param dyConsumed target 已经消费的y方向的距离
	 * @param dxUnconsumed x 方向剩下的未消费的距离
	 * @param dyUnconsumed y 方向剩下的未消费距离
	 * @param type
	 */
	@Override
	public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
		Log.e(TAG, "onNestedScroll:child=" + child + "   target=" + target + "   dxConsumed=" + dxConsumed + "   dyConsumed=" + dyConsumed + "   dxUnconsumed=" + dxUnconsumed + "   dyUnconsumed=" + dyUnconsumed + "   type=" + type);

		if (dyUnconsumed >= 0) {
			//向上滑动不处理
			return;
		}

		View view = mDependencyView.get();
		if (view.getTranslationY() != 0) {
			float newTranslationY = view.getTranslationY() - dyUnconsumed;
			newTranslationY = newTranslationY < 0 ? newTranslationY : 0;
			onScroll(newTranslationY, false);
			view.setTranslationY(newTranslationY);
		}
	}

	/**
	 * 嵌套滚动结束时被调用，这是一个清除滚动状态等的好时机。
	 * @param coordinatorLayout
	 * @param child
	 * @param target
	 * @param type
	 */
	@Override
	public void onStopNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int type) {
		Log.d(TAG, "onStopNestedScroll: child=" + child + "   target=" + target + "   type=" + type);
		super.onStopNestedScroll(coordinatorLayout, child, target, type);
		onUserStopDrag();
	}

	private void onUserStopDrag() {
		RelativeLayout dependency = mDependencyView.get();
		final float translationY = dependency.getTranslationY();

		float endFloat = 0;
		int halfDistance = (mMaxHeadHeight - mMinHeadHeight) / 2;
		if (Math.abs(translationY) > halfDistance) {
			endFloat = mMinHeadHeight - mMaxHeadHeight;
		}

		final boolean scrollUp = endFloat != 0;
		mValueAnimator = ValueAnimator.ofFloat(translationY, endFloat).setDuration(200);
		mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				float translateY = (float) animation.getAnimatedValue();
				onScroll(translateY, scrollUp);
				mDependencyView.get().setTranslationY(translateY);
			}
		});
		mValueAnimator.start();
	}

	/**
	 * 用户松开手指并且会发生惯性动作之前调用，参数提供了速度信息，可以根据这些速度信息
	 * 决定最终状态，比如滚动Header，是让Header处于展开状态还是折叠状态。返回true 表
	 * 示消费了fling.
	 * @param coordinatorLayout
	 * @param child
	 * @param target
	 * @param velocityX x 方向的速度
	 * @param velocityY y 方向的速度
	 * @return
	 */
	@Override
	public boolean onNestedPreFling(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, float velocityX, float velocityY) {
		Log.d(TAG, "onNestedPreFling: child=" + child + "   target=" + target + "   velocityX=" + velocityX + "   velocityY=" + velocityY);

		RelativeLayout dependency = mDependencyView.get();
		if (velocityY > mMaxHeadHeight) {
			//向上滑动，超过最大头部高度
			//			dependency.setTranslationY(mMinHeadHeight - mMaxHeadHeight);
		} else if (velocityY < -mMaxHeadHeight) {
			//向下滑动，超过最大头部高度
			//			dependency.setTranslationY(0);
		}
		return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
	}

	/**
	 *
	 * @param coordinatorLayout
	 * @param child
	 * @param target
	 * @param velocityX
	 * @param velocityY
	 * @param consumed
	 * @return
	 */
	@Override
	public boolean onNestedFling(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, float velocityX, float velocityY, boolean consumed) {
		Log.d(TAG, "onNestedFling: child=" + child + "   target=" + target + "   velocityX=" + velocityX + "   velocityY=" + velocityY + "   consumed=" + consumed);
		return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
	}

	//可以重写这个方法对子View 进行重新布局
	@Override
	public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
		Log.i(TAG, "onLayoutChild.....");
		CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
		if (lp.height == CoordinatorLayout.LayoutParams.MATCH_PARENT) {
			RelativeLayout rlHead = parent.findViewById(R.id.rl_head);
			init(parent, rlHead);
			Resources resources = parent.getResources();
			child.layout(0, getCollapsingHeight(resources), parent.getWidth(), parent.getHeight());
			return true;
		}
		return super.onLayoutChild(parent, child, layoutDirection);
	}


	private void init(CoordinatorLayout parent, RelativeLayout dependency) {
		if (mDependencyView == null) {
			mDependencyView = new WeakReference<>(dependency);
		}

		if (mTvName == null) {
			TextView tvName = parent.findViewById(R.id.tv_name);
			mTvName = new WeakReference<>(tvName);
		}

		if (mTvTempName == null) {
			TextView tvTempName = parent.findViewById(R.id.tv_temp_name);
			mTvTempName = new WeakReference<>(tvTempName);
		}

		int[] loc = new int[2];
		if (mTitleStartX <= 0 || mTitleStartY <= 0) {
			TextView tvName = parent.findViewById(R.id.tv_name);
			tvName.getLocationInWindow(loc);
			mTitleStartX = loc[0];
			mTitleStartY = loc[1] - Utils.getStatusBarHeight(mContext);

			ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mTvTempName.get().getLayoutParams();
			params.leftMargin = mTitleStartX;
			params.topMargin = mTitleStartY;
			mTvTempName.get().setLayoutParams(params);
		}

		if (mTitleEndX <= 0 || mTitleEndY <= 0) {
			Arrays.fill(loc, 0);
			TextView tvTitle = parent.findViewById(R.id.tv_title);
			tvTitle.getLocationInWindow(loc);
			mTitleEndX = loc[0];
			mTitleEndY = loc[1] - Utils.getStatusBarHeight(mContext);
		}
	}

	/**
	 * 获取顶部栏的高度
	 * @return
	 */
	private int getMaxHeadViewHeight() {
		if (mMaxHeadHeight <= 0 && mDependencyView.get() != null) {
			mMaxHeadHeight = mDependencyView.get().getMeasuredHeight();
		}
		return mMaxHeadHeight;
	}

	private int getCollapsingHeight(Resources resources) {
		if (mMinHeadHeight <= 0) {
			mMinHeadHeight = resources.getDimensionPixelSize(R.dimen.top_bar_height);
		}
		return mMinHeadHeight;
	}


	/**
	 * 打印当前线程的调用堆栈
	 *
	 */
	public static void printTrack() {
		StackTraceElement[] st = Thread.currentThread().getStackTrace();
		if (st == null) {
			System.out.println("无堆栈...");
			return;
		}
		StringBuffer sbf = new StringBuffer();
		for (StackTraceElement e : st) {
			if (sbf.length() > 0) {
				sbf.append(" <- ");
				sbf.append(System.getProperty("line.separator"));
			}
			sbf.append(java.text.MessageFormat.format("{0}.{1}() {2}", e.getClassName(), e.getMethodName(), e.getLineNumber()));
		}
		Log.i("AAA", sbf.toString());
	}

}
